package com.zhiche.wms.service.inbound.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.toolkit.CollectionUtils;
import com.google.common.base.Strings;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.zhiche.wms.configuration.MyConfigurationProperties;
import com.zhiche.wms.core.supports.BaseException;
import com.zhiche.wms.core.supports.enums.InterfaceAddrEnum;
import com.zhiche.wms.core.supports.enums.InterfaceEventEnum;
import com.zhiche.wms.core.supports.enums.TableStatusEnum;
import com.zhiche.wms.core.utils.HttpClientUtil;
import com.zhiche.wms.domain.mapper.base.StorehouseMapper;
import com.zhiche.wms.domain.mapper.inbound.FactoryPrepareInboundMapper;
import com.zhiche.wms.domain.mapper.inbound.InboundNoticeHeaderMapper;
import com.zhiche.wms.domain.mapper.inbound.InboundNoticeLineMapper;
import com.zhiche.wms.domain.mapper.inbound.InboundPutawayLineMapper;
import com.zhiche.wms.domain.mapper.log.ItfExplogLineMapper;
import com.zhiche.wms.domain.mapper.otm.OtmOrderReleaseMapper;
import com.zhiche.wms.domain.mapper.otm.OtmShipmentMapper;
import com.zhiche.wms.domain.mapper.stock.StockMapper;
import com.zhiche.wms.domain.model.base.StoreLocation;
import com.zhiche.wms.domain.model.base.Storehouse;
import com.zhiche.wms.domain.model.inbound.*;
import com.zhiche.wms.domain.model.log.ItfExplogLine;
import com.zhiche.wms.domain.model.otm.OtmOrderRelease;
import com.zhiche.wms.domain.model.stock.SkuStore;
import com.zhiche.wms.domain.model.sys.User;
import com.zhiche.wms.dto.inbound.*;
import com.zhiche.wms.dto.opbaas.paramdto.CommonConditionParamDTO;
import com.zhiche.wms.service.base.IStoreLocationService;
import com.zhiche.wms.service.common.IntegrationService;
import com.zhiche.wms.service.constant.PutAwayType;
import com.zhiche.wms.service.constant.SourceSystem;
import com.zhiche.wms.service.constant.Status;
import com.zhiche.wms.service.dto.OTMEvent;
import com.zhiche.wms.service.inbound.IInboundNoticeHeaderService;
import com.zhiche.wms.service.inbound.IInboundNoticeLineService;
import com.zhiche.wms.service.inbound.IInboundPutawayHeaderService;
import com.zhiche.wms.service.opbaas.ExceptionToOTMService;
import com.zhiche.wms.service.opbaas.IOrderReleaseService;
import com.zhiche.wms.service.otm.IOtmShipmentService;
import com.zhiche.wms.service.stock.ISkuStoreService;
import com.zhiche.wms.service.sys.IUserService;
import com.zhiche.wms.service.utils.BusinessNodeExport;
import com.zhiche.wms.service.utils.CommonFields;
import com.zhiche.wms.service.utils.CommonMethod;
import com.zhiche.wms.service.utils.WmsMethodUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.*;


/**
 * <p>
 * 入库通知明细 服务实现类
 * </p>
 *
 * @author qichao
 * @since 2018-06-08
 */
@Service
public class InboundNoticeLineServiceImpl extends ServiceImpl<InboundNoticeLineMapper, InboundNoticeLine> implements IInboundNoticeLineService {

    private static final Logger LOGGER = LoggerFactory.getLogger(InboundNoticeLineServiceImpl.class);

    private static final int black = 0xFF000000;
    private static final int white = 0xFFFFFFFF;
    @Autowired
    private IInboundPutawayHeaderService iinboundPutawayHeaderService;
    @Autowired
    InboundPutawayLineMapper inboundPutawayLineMapper;
    @Autowired
    private IStoreLocationService iStoreLocationService;
    @Autowired
    private IOrderReleaseService releaseService;
    @Autowired
    private ISkuStoreService skuStoreService;
    @Autowired
    private IUserService userService;
    @Autowired
    private ExceptionToOTMService exceptionToOTMService;
    @Autowired
    private OtmOrderReleaseMapper otmOrderReleaseMapper;
    @Autowired
    private StorehouseMapper storehouseMapper;
    @Autowired
    private InboundNoticeHeaderMapper inboundNoticeHeaderMapper;
    @Autowired
    private ItfExplogLineMapper itfExplogLineMapper;
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private InboundNoticeLineMapper inboundNoticeLineMapper;
    @Autowired
    private IntegrationService integrationService;
    @Autowired
    private BusinessNodeExport nodeExport;
    @Autowired
    private IInboundNoticeHeaderService inboundNoticeHeaderService;
    @Autowired
    private FactoryPrepareInboundMapper factoryPrepareInboundMapper;
    @Autowired
    private OtmShipmentMapper otmShipmentMapper;
    @Autowired
    private IOtmShipmentService iOtmShipmentService;

    @Override
    public boolean updateInboundStatus (Long headerId, Long noticeLineId) {
        return baseMapper.updateStatus(headerId,noticeLineId) > 0;
    }

    @Autowired
    private MyConfigurationProperties properties;
    /**
     * 分配入库-模糊查询
     */
    @Override
    public Page<InboundNoticeDTO> selectInboundsPage(String key, Long houseId, Integer size, Integer current) {
        try {
            if (Strings.isNullOrEmpty(key)) {
                throw new BaseException("订单号或车架号为空");
            }
            EntityWrapper<OtmOrderRelease> oorEW = new EntityWrapper<>();
            oorEW.eq("qr_code", key)
                    .ne("status", TableStatusEnum.STATUS_50.getCode())
                    .orderBy("id", false);
            OtmOrderRelease release = releaseService.selectOne(oorEW);
            if (release != null) {
                key = release.getVin();
            }
            Page<InboundNoticeDTO> page = new Page<>(current, size);
            EntityWrapper<InboundNoticeDTO> ew = new EntityWrapper<>();
            //增加模糊条件   放开可以查询到已入库数据库位展示
            ew.eq("store_house_id", houseId)
                    .notIn("status", TableStatusEnum.STATUS_50.getCode())
                    .andNew()
                    .like("owner_order_no", key)
                    .or()
                    .like("lot_No1", key)
                    .or()
                    .eq("qr_code", key)
                    .orderBy("gmt_create", false)
                    .orderBy("id", false);
            List<InboundNoticeDTO> dtos = this.baseMapper.queryPageNotice(page, ew);
            if (CollectionUtils.isEmpty(dtos)) {
                throw new BaseException("未查询到key:" + key + "入库信息");
            }
            //设值
            page.setRecords(dtos);
            return page;
        } catch (BaseException e) {
            LOGGER.error("Service:\t" + e.toString());
            throw e;
        } catch (Exception e) {
            LOGGER.error("Service:\t" + e.toString());
            throw new BaseException("数据库查询出现错误");
        }
    }

    /**
     * 查询详情根据id号
     */
    @Override
    public InboundNoticeDTO selectInbound(Long LineId, Long houseId) {
        try {
            InboundNoticeDTO notice = baseMapper.getNoticeByLineId(LineId, houseId);
            EntityWrapper<SkuStore> skuStoreEW = new EntityWrapper<>();
            skuStoreEW.eq("vin", notice.getLotNo1())
                    .eq("store_house_id", houseId)
                    .orderBy("id", false);
            SkuStore skuStore = skuStoreService.selectOne(skuStoreEW);
            if (skuStore != null) {
                notice.setStoreDetail(skuStore.getStoreDetail());
            }
            //查询该车是否异常发运
            String send = exceptionToOTMService.isSend(notice.getLotNo1(), notice.getStoreHouseName());
            if (!org.springframework.util.StringUtils.isEmpty(send)) notice.setIsCanSend(send);
            return notice;
        } catch (BaseException e) {
            LOGGER.error("Service:\t" + e.toString());
            throw e;
        } catch (Exception e) {
            LOGGER.error("Service:\t" + e.toString());
            throw new BaseException("详情查询出现异常");
        }
    }

    /**
     * 查询详情根据二维码号
     */
    @Override
    public InboundNoticeDTO selectInboundByQrCode(String key, Long houseId) {
        if (Strings.isNullOrEmpty(key)) {
            throw new BaseException("订单号或车架号为空");
        }
        //fix  2018-1-30 调整多个入库通知单扫码入库 提示异常
        EntityWrapper<OtmOrderRelease> oorEW = new EntityWrapper<>();
        oorEW.eq("qr_code", key)
                .ne("status", TableStatusEnum.STATUS_50.getCode())
                .orderBy("id", false);
        List<OtmOrderRelease> orderReleases = releaseService.selectList(oorEW);
        if (CollectionUtils.isNotEmpty(orderReleases)) {
            key = orderReleases.get(0).getVin();
        }
        List<InboundNoticeDTO> dtos = baseMapper.getNoticeByKey(key, houseId);
        if (CollectionUtils.isNotEmpty(dtos)) {
            InboundNoticeDTO noticeDTO = dtos.get(0);
            EntityWrapper<SkuStore> skuStoreEW = new EntityWrapper<>();
            skuStoreEW.eq("vin", noticeDTO.getLotNo1())
                    .eq("store_house_id", houseId)
                    .orderBy("id", false);
            SkuStore skuStore = skuStoreService.selectOne(skuStoreEW);
            if (skuStore != null) {
                noticeDTO.setStoreDetail(skuStore.getStoreDetail());
            }
            //查询该车是否异常发运
            String send = exceptionToOTMService.isSend(noticeDTO.getLotNo1(), noticeDTO.getStoreHouseName());
            if (StringUtils.isNotBlank(send)) {
                noticeDTO.setIsCanSend(send);
            }
            return noticeDTO;
        }
        return null;
    }

    /**
     * 查询详情根据HeaderId
     */
    public List<InboundNoticeDTO> selectInboundByHeadId(Long headId, Long houseIds) {
        try {
            EntityWrapper<InboundNoticeDTO> ew = new EntityWrapper<>();
            //增加模糊条件
            ew.eq("header_id", headId).eq("store_house_id", houseIds);
            //设值
            return this.baseMapper.queryListNotice(ew);
        } catch (BaseException e) {
            LOGGER.error("Service:\t" + e.toString());
            throw e;
        } catch (Exception e) {
            LOGGER.error("Service:\t" + e.toString());
            throw new BaseException("模糊搜索出现异常");
        }
    }
    //未收取钥匙的已入库车辆信息 hgy 20200825
    public Page<InboundPutawayDTO> selectNoKeyTask(Page<InboundPutawayDTO> page) {
        try {
            if (Objects.isNull(page)) throw new Exception("参数为空");
            EntityWrapper<InboundPutawayDTO> ew = new EntityWrapper<>();
            //增加模糊条件
            Map<String,Object> condition = page.getCondition();
            Object houseId = condition.get("houseId");
            if (!Objects.isNull(houseId)) ew.eq("store_house_id", houseId);

            Object lotNo1 = condition.get("key");
            if (!Objects.isNull(lotNo1) && StringUtils.isNotBlank(lotNo1.toString())) {
                String vin = lotNo1.toString();
                ew.like("lot_no1", vin);
            }
            //执行查询操作
            ew.orderBy("id", false);
            List<InboundPutawayDTO> inboundDTOS = this.baseMapper.queryInboundNoKeyPage(page, ew);
            //将结果集保存至page返回
            page.setRecords(inboundDTOS);
            return page;
        } catch (BaseException e) {
            //进行自定义异常的抛出
            LOGGER.error("Service:\t" + e.toString());
            throw e;
        } catch (Exception e) {
            LOGGER.error("Service:\t" + e.toString());
            throw new BaseException("模糊搜索出现异常");
        }
    }

    public Page<InboundDTO> selectInboundTask(Page<InboundDTO> page) {
        try {
            if (Objects.isNull(page)) throw new Exception("参数为空");
            EntityWrapper<InboundDTO> ew = new EntityWrapper<>();
            //增加模糊条件
            Map<String,Object> condition = page.getCondition();
            Object houseId = condition.get("houseId");
            if (!Objects.isNull(houseId)) ew.eq("store_house_id", houseId);

            Object id = condition.get("key");
            if (!Objects.isNull(id)) ew.like("owner_order_no", id.toString());

            Object ownerId = condition.get("ownerId");
            if (!Objects.isNull(ownerId)) ew.like("owner_id", ownerId.toString());

            Object status = condition.get("status");
            if (status != null && StringUtils.isNotBlank(status.toString())) {
                if(TableStatusEnum.STATUS_40.getCode().equals(status)){
                    ew.eq("remarks", "取消入库");
                }else {
                    ew.eq("status", status.toString());
                }

            } else {
                ew.ne("status", TableStatusEnum.STATUS_50.getCode());
            }
            if (Objects.nonNull(condition.get("startDate")) && StringUtils.isNotEmpty((String) condition.get("startDate"))) {
                ew.ge("inbound_modified", condition.get("startDate").toString());
            }
            if (Objects.nonNull(condition.get("endDate")) && StringUtils.isNotEmpty((String) condition.get("endDate"))) {
                ew.le("inbound_modified", condition.get("endDate").toString());
            }

            Object lotNo1 = condition.get("lotNo1");
            if (!Objects.isNull(lotNo1) && StringUtils.isNotBlank(lotNo1.toString())) {
                String vin = lotNo1.toString();
                List<String> vins = Arrays.asList(CommonMethod.setVins(lotNo1.toString()));
                ew.andNew().in("lot_no1", vins).or().like("lot_no1", vin);
            }
            //执行查询操作
            ew.orderBy("id", false);
            List<InboundDTO> inboundDTOS = this.baseMapper.queryInboundDetailPage(page, ew);
            //将结果集保存至page返回
            page.setRecords(inboundDTOS);
            return page;
        } catch (BaseException e) {
            //进行自定义异常的抛出
            LOGGER.error("Service:\t" + e.toString());
            throw e;
        } catch (Exception e) {
            LOGGER.error("Service:\t" + e.toString());
            throw new BaseException("模糊搜索出现异常");
        }
    }

    @Override
    public List<InboundDTO> queryExportData(Map<String, String> condition) {
        if (condition == null || condition.isEmpty()) {
            throw new BaseException("参数不能为空");
        }
        String houseId = condition.get("houseId");
        if (StringUtils.isBlank(houseId)) {
            throw new BaseException("仓库信息不能为空");
        }
        EntityWrapper<InboundDTO> ew = new EntityWrapper<>();
        //增加模糊条件
        ew.eq("store_house_id", houseId);
        String orderNo = condition.get("orderNo");
        if (StringUtils.isNotBlank(houseId)) {
            ew.like("owner_order_no", orderNo);
        }
        String lotNo1 = condition.get("lotNo1");
        if (StringUtils.isNotBlank(lotNo1)) {
            ew.like("lot_no1", lotNo1);
        }
        String ownerId = condition.get("ownerId");
        if (StringUtils.isNotBlank(ownerId)) {
            ew.like("owner_id", ownerId);
        }
        String status = condition.get("status");
        if (StringUtils.isNotBlank(status)) {
            ew.eq("status", status);
        }
        if (Objects.nonNull(condition.get("startDate")) && StringUtils.isNotEmpty((String) condition.get("startDate"))) {
            ew.ge("inboundTime", condition.get("startDate").toString());
        }
        if (Objects.nonNull(condition.get("endDate")) && StringUtils.isNotEmpty((String) condition.get("endDate"))) {
            ew.le("inboundTime", condition.get("endDate").toString());
        }
        //执行查询操作
        ew.orderBy("id", false);
        List<InboundDTO> list = this.baseMapper.queryExportData(ew);
        return list;
    }

    /**
     * 入库通知单查询
     */
    @Override
    public List<InboundNoticeLine> pageInboundNotice(Page<InboundNoticeLine> page, EntityWrapper<InboundNoticeLine> inEW) {
        return baseMapper.pageInboundNotice(page, inEW);
    }

    @Override
    public int selectCountWithHead(EntityWrapper<InboundNoticeLine> noticeLineEntityWrapper) {
        return baseMapper.selectCountWithHead(noticeLineEntityWrapper);
    }

    @Override
    public List<String> storeHousePutway (String key) {
        List<String> result = new ArrayList<>();
        if (StringUtils.isEmpty(key)) {
            throw new BaseException("仓库【key】不能为空！");
        }
        EntityWrapper<InboundNoticeLine> headerEw = new EntityWrapper<>();
        List<String> headerStatus = new ArrayList<>();
        headerStatus.add(TableStatusEnum.STATUS_40.getCode());
        headerStatus.add(TableStatusEnum.STATUS_50.getCode());
        headerEw.in("a.store_house_id", Arrays.asList(key.split(",")));
        headerEw.notIn("a.status", headerStatus);
        headerEw.eq("b.status", TableStatusEnum.STATUS_10.getCode());
        List<InboundNoticeLine> noticeLines = inboundNoticeLineMapper.queryStoreHousePutway(headerEw);
        if (CollectionUtils.isEmpty(noticeLines)) {
            throw new BaseException("入库明细为空！");
        }
        //查询通知单明细
        for (InboundNoticeLine line : noticeLines) {
            StringBuilder sb = new StringBuilder();
            try {
                iinboundPutawayHeaderService.updateByNoticeLineId(line.getId(), PutAwayType.NOTICE_PUTAWAY, SourceSystem.HAND_MADE, null);
            } catch (BaseException e) {
                sb.append("车架号:").append(line.getLotNo1()).append(":").append(e.getMessage());
            } catch (Exception ex) {
                sb.append("车架号:").append(line.getLotNo1()).append(":系统异常");
            }
            if (StringUtils.isNotEmpty(sb)) {
                result.add(sb.toString());
            }
        }
        LOGGER.info("result{}" ,result);
        return result;
    }

    @Override
    public Page<ShipmentInbound> queryInboundData (Page<ShipmentInbound> page) {
        List<ShipmentInbound> shipmentInbounds = baseMapper.queryInboundData(page);
        LOGGER.info("数据监控查询入库数据shipmentInbounds为：{}",shipmentInbounds);
        return page.setRecords(shipmentInbounds);
    }

    @Override
    public Page<ItfExplogLine> queryPushInboundOtm (Page<ItfExplogLine> page) {
        //1、判断用户是否登录
        User loginUser = userService.getLoginUser();
        if (loginUser == null) {
            throw new BaseException("未查询到登录用户");
        }

        //2、组装筛选条件
        EntityWrapper<ItfExplogLine> ew = new EntityWrapper<>();
        Map<String, Object> conditions = page.getCondition();
        if (Objects.nonNull(conditions)) {
            if (Objects.nonNull(conditions.get("shipmentGid")) && StringUtils.isNotEmpty((String) conditions.get("shipmentGid"))) {
                ew.like("inh.source_key", conditions.get("shipmentGid").toString());
            }
            if (Objects.nonNull(conditions.get("vin")) && StringUtils.isNotEmpty((String) conditions.get("vin"))) {
                List<String> vins = Arrays.asList(CommonMethod.setVins((String) conditions.get("vin")));
                ew.in("inl.lot_no1", vins);
            }
            if (Objects.nonNull(conditions.get("requestId")) && StringUtils.isNotEmpty((String) conditions.get("requestId"))) {
                ew.eq("iel.request_id", conditions.get("requestId"));
            }

            if (Objects.nonNull(conditions.get("storeHouseId")) && StringUtils.isNotEmpty((String) conditions.get("storeHouseId"))) {
                ew.eq("inh.store_house_id", conditions.get("storeHouseId"));
            }

            if (Objects.nonNull(conditions.get("storeHouseName")) && StringUtils.isNotEmpty((String) conditions.get("storeHouseName"))) {
                ew.like("ws.name", String.valueOf(conditions.get("storeHouseName")));
            }
        }
        ew.eq("iel.export_type", "BS_WMS_IN");
        ew.orderBy("gmt_modified", false);

        //3、查询信息
        List<ItfExplogLine> list = itfExplogLineMapper.queryPushInboundToOtm(page,ew);
        return page.setRecords(list);
    }

    @Override
    public void pushInboundOtm (Page<ItfExplogLine> page) {
        Map<String, Object> condition = page.getCondition();
        if (Objects.isNull(condition)) {
            throw new BaseException("入参不能为空");
        }
        if (Objects.isNull(condition.get("keys")) || StringUtils.isEmpty((String)condition.get("keys")) ) {
            throw new BaseException("入参[keys]不能为空");
        }

        User loginUser = userService.getLoginUser();
        if (loginUser == null) {
            throw new BaseException("未查询到登录用户");
        }

        List<String> ids = Arrays.asList(condition.get("keys").toString().split(","));
        EntityWrapper<ItfExplogLine> ew = new EntityWrapper<>();
        ew.in("id", ids);
        List<ItfExplogLine> itfExplogLines = itfExplogLineMapper.selectList(ew);
        LOGGER.info("查询结果为{}", itfExplogLines);
        if (CollectionUtils.isNotEmpty(itfExplogLines)) {
            for (ItfExplogLine itfExplogLine : itfExplogLines) {
                //3、推送数据至OTM
                LOGGER.info("补发入库数据推送OTM入参：{}", itfExplogLine.getDataContent());

                //TODO 添加推送日志到日志系统

                String requestId = WmsMethodUtils.pushSystemData(properties.getIntegrationhost() + InterfaceAddrEnum.EVENT_URI.getAddress(),
                        itfExplogLine.getDataContent());
                if(StringUtils.isNotEmpty(requestId)){
                    ItfExplogLine param = new ItfExplogLine();
                    param.setRequestId(requestId);
                    param.setUserCreate(loginUser.getName());
                    param.setId(itfExplogLine.getId());
                    itfExplogLineMapper.updateById(param);
                }
            }
        }
    }

    @Override
    public String cancleInbound (List<String> params) {
        StringBuffer sb = new StringBuffer();
        //参数校验
        if(CollectionUtils.isEmpty(params)){
            throw new BaseException("取消入库参数不能为空");
        }
        User loginUser = userService.getLoginUser();
        if (loginUser == null) {
            throw new BaseException("未查询到登录用户");
        }

        //1、查询是否已入库，未入库的不需要入库\
        EntityWrapper<InboundNoticeLine> inboundEw = new EntityWrapper<>();
        inboundEw.in("id", params);
        List<InboundNoticeLine> inboundList = baseMapper.selectList(inboundEw);
        if(CollectionUtils.isEmpty(inboundList)){
            throw new BaseException("取消入库查询结果为空，请重新确认");
        }
        for (InboundNoticeLine inbound : inboundList){
            if(TableStatusEnum.STATUS_30.getCode().equals(inbound.getStatus())){
                //2、取消入库
                this.cancleInboundNoticeLine(inbound,loginUser.getName());
            }else{
                sb.append("车架号：").append(inbound.getLotNo1()).append("状态不是【已入库】状态，不能取消入库");
            }
        }
        return sb.toString();
    }

    @Override
    public Page<CancleInboundDTO> queryCancleInbound (Page<CancleInboundDTO> page) {
        EntityWrapper<CancleInboundDTO> inboundEw = new EntityWrapper<>();
        Map<String, Object> condition = page.getCondition();
        if (null != condition && !condition.isEmpty()) {
            if (StringUtils.isNotEmpty((String) condition.get("storeHouseId"))) {
                inboundEw.like("wh.name",(String)condition.get("storeHouseId"));
            }

            if (StringUtils.isNotEmpty((String) condition.get("vin"))) {
                String vins[] = CommonMethod.setVins((String) condition.get("vin"));
                inboundEw.in("ipl.lot_no1", vins).or().like("ipl.lot_no1", (String) condition.get("vin"));
            }
            inboundEw.orderBy("ipl.gmt_modified", false);
        }
        List<CancleInboundDTO> cancleInboundDTOS = baseMapper.queryCancleInbound(inboundEw,page);
        return page.setRecords(cancleInboundDTOS);
    }

    /**
     * 取消入库
     * @param inbound 入库记录
     * @param userName 登录用户
     */
    private void cancleInboundNoticeLine (InboundNoticeLine inbound, String userName) {
        //1、初始化入库状态为10
        //更改明细表
        InboundNoticeLine inboundNoticeLine = new InboundNoticeLine();
        inbound.setCancleUser(userName);
        inboundNoticeLine.setId(inbound.getId());
        inboundNoticeLine.setStatus(TableStatusEnum.STATUS_10.getCode());
        inboundNoticeLine.setIsCancle(TableStatusEnum.STATUS_1.getCode());
        baseMapper.updateById(inboundNoticeLine);
        //更改头表
        InboundNoticeHeader inboundNoticeHeader = new InboundNoticeHeader();
        inboundNoticeHeader.setId(inbound.getHeaderId());
        inboundNoticeHeader.setStatus(TableStatusEnum.STATUS_10.getCode());
        inboundNoticeHeaderMapper.updateById(inboundNoticeHeader);

        //2、删除入库记录
        EntityWrapper<InboundPutawayHeader> inboundPutawayHeaderEW = new EntityWrapper<>();
        inboundPutawayHeaderEW.eq("notice_id",inbound.getHeaderId());
        iinboundPutawayHeaderService.delete(inboundPutawayHeaderEW);

        EntityWrapper<InboundPutawayLine> inboundPutawayLineEW = new EntityWrapper<>();
        inboundPutawayLineEW.eq("notice_line_id",inbound.getId());
        inboundPutawayLineMapper.delete(inboundPutawayLineEW);

        //3、清理库存为0
        this.dealSku(inbound);

        //4、运单状态如果为已入库是否需要改为BS_DISPATCH
        EntityWrapper<OtmOrderRelease> oorEw = new EntityWrapper<>();
        oorEw.eq("release_gid", inbound.getLineSourceKey());
        oorEw.ne("status", TableStatusEnum.STATUS_50.getCode());
        List<OtmOrderRelease> release = otmOrderReleaseMapper.selectList(oorEw);
        if (CollectionUtils.isEmpty(release)) {
            throw new BaseException(inbound.getLotNo1() + "对应的运单信息为空");
        }
        oorEw.eq("status", TableStatusEnum.STATUS_BS_INBOUND.getCode());
        List<OtmOrderRelease> inboundRelease = otmOrderReleaseMapper.selectList(oorEw);
        if (CollectionUtils.isNotEmpty(inboundRelease)) {
            OtmOrderRelease otmOrderRelease = new OtmOrderRelease();
            otmOrderRelease.setStatus(TableStatusEnum.STATUS_BS_DISPATCH.getCode());
            otmOrderRelease.setRemarks("取消入库后更改");
            otmOrderReleaseMapper.update(otmOrderRelease,oorEw);
        }

        this.cancleInboundToOTM(inbound.getId(),release.get(0).getReleaseGid(),release.get(0).getShipmentGid());

    }

    /**
     * 取消入库增加字段
     *
     * @param noticeLineId 通知单详细信息id
     * @param releaseGid   运单号
     * @param shipmentGid  指令号
     */
    private void cancleInboundToOTM (Long noticeLineId, String releaseGid, String shipmentGid) {
        OTMEvent event = integrationService.getOtmEvent(String.valueOf(noticeLineId),
                releaseGid,
                InterfaceEventEnum.BS_CANCLE_WMS_IN.getCode(),
                shipmentGid,
                "取消入库回传OTM");
        String res = nodeExport.exportEventToOTM(event);
        try {
            integrationService.insertExportLog(
                    String.valueOf(noticeLineId),
                    event, res, "取消入库回传OTM",
                    InterfaceEventEnum.BS_CANCLE_WMS_IN.getCode());
        } catch (Exception e) {
            LOGGER.error("取消入库推送OTM失败:{}", e);
            throw new BaseException("取消入库推送OTM失败");
        }
    }

    private void dealSku (InboundNoticeLine inbound) {
        EntityWrapper<InboundNoticeHeader> inbundHeaderEw = new EntityWrapper<>();
        inbundHeaderEw.eq("id", inbound.getHeaderId());
        inbundHeaderEw.ne("Status",TableStatusEnum.STATUS_50.getCode());
        List<InboundNoticeHeader> inboundNoticeHeaders = inboundNoticeHeaderMapper.selectList(inbundHeaderEw);

        //更新库存为0
        Map<String,Object> sqlParam = new HashMap<>();
        sqlParam.put("storeHouseId",inboundNoticeHeaders.get(0).getStoreHouseId());
        sqlParam.put("lotNo1",inbound.getLotNo1());
        stockMapper.dealEmptySku(sqlParam);
    }


    public List<String> updateInboundConfirm (List<Long> ids, Long houseId, Long areaId) {
        LOGGER.info("入库确认 主键id ： {} 仓库houseId : 为{}", ids, houseId);
        List<String> result = new ArrayList<>();
        if (Objects.isNull(ids) || ids.size() == 0) {
            throw new BaseException("未获取到选中列");
        }
        List<String> shipmentStatus = new ArrayList<>();
        //查询通知单明细
        EntityWrapper<InboundNoticeLine> ew = new EntityWrapper<>();
        ew.in("id", ids);
        List<InboundNoticeLine> noticeLines = selectList(ew);
        for (InboundNoticeLine line : noticeLines) {
            StringBuilder sb = new StringBuilder();
            try {
                if (StringUtils.isNotBlank(line.getLineSourceKey())) {
                    String shipmentXid = inboundNoticeHeaderMapper.selectSourceKeyByLineId(line.getId(), line.getLineSourceKey());
                    if (StringUtils.isNotBlank(shipmentXid) && !queryShipmentStatusByOtm(shipmentXid) && !shipmentStatus.contains(shipmentXid)) {
                        iOtmShipmentService.deleteShipmentInfo(shipmentXid);
                        shipmentStatus.add(shipmentXid);
                        sb.append("车架号:").append(line.getLotNo1()).append(":").append("和ILS系统数据不一致，已调整！");
                        result.add(sb.toString());
                        continue;
                    }
                }
            } catch (Exception e) {
                LOGGER.error("OTM查询指令状态信息异常{}", e.getMessage());
            }

            //工厂未备料数据是否有未出库的车辆
            EntityWrapper<FactoryPrepareInbound> fpiEw = new EntityWrapper<>();
            fpiEw.eq(CommonFields.VIN.getCode(), line.getLotNo1());
            fpiEw.eq("prepare_status", TableStatusEnum.STATUS_10.getCode());
            List<FactoryPrepareInbound> fpiList = factoryPrepareInboundMapper.selectList(fpiEw);
            if (CollectionUtils.isNotEmpty(fpiList)) {
                sb.append("车架号:").append(line.getLotNo1()).append(":").append("有无单入库的数据还未出库！");
                result.add(sb.toString());
                continue;
            }

            //查询是否已经取消入库
            if (TableStatusEnum.STATUS_50.getCode().equals(line.getStatus()) || TableStatusEnum.STATUS_40.getCode().equals(line.getStatus())) {
                LOGGER.info("车架号{}状态为取消状态。。。。", line.getLotNo1());
                throw new BaseException("客户单号" + line.getOwnerOrderNo() + "对应的车架号" + line.getLotNo1() + "不能确认入库，请确认其状态!");
            }

            try {
                //查询下段是否指令删除
                isQuit(line.getHeaderId(), line.getLotNo1(), line.getStatus());
                //入库操作
                iinboundPutawayHeaderService.updateByNoticeLineId(line.getId(), PutAwayType.NOTICE_PUTAWAY, SourceSystem.HAND_MADE, areaId);
            } catch (BaseException e) {
                sb.append("车架号:").append(line.getLotNo1()).append(":").append(e.getMessage());
            } catch (Exception ex) {
                sb.append("车架号:").append(line.getLotNo1()).append(":系统异常");
            }
            if (StringUtils.isNotBlank(sb)) {
                result.add(sb.toString());
            }
        }
        return result;
    }

    /**
     * 查询OTM是否有指令信息
     *
     * @param shipmentXid 指令号
     */
    private boolean queryShipmentStatusByOtm (String shipmentXid) {
        try {
            //组装数据给OTM
            Map<String, String> param = new HashMap<>();
            param.put("shipmentXid", shipmentXid);
            String jsonParam = JSONObject.toJSONString(param);
            String result = HttpClientUtil.postJson(properties.getOtmhost() + InterfaceAddrEnum.QUERYISSHIPMENT_OTM.getAddress(), null, jsonParam,
                    properties.getSocketTimeOut());
            LOGGER.info("查询指令状态 result:{},{}", result, shipmentXid);
            if (StringUtils.isNotBlank(result)) {
                JSONObject jsonObject = JSONObject.parseObject(result);
                if (jsonObject.getString("success").equals("false") && jsonObject.getString("data").equals(TableStatusEnum.STATUS_N.getCode())) {
                    return false;
                }
            }
        } catch (Exception e) {
            LOGGER.error("otm查询指令状态异常！" + e.getMessage());
        }
        return true;
    }

    /**
     * 查询下单指令是否删除
     *
     * @param headerId 入库头id
     * @param vin      车架号
     */
    private void isQuit (Long headerId, String vin, String status) {
        LOGGER.info("查询是否有已入库但是被删除的数据",vin);
        List<String> cancleOutboundList = null;
        try {
            if (!status.equals(Status.Inbound.ALL)) {
                return;
            }

            InboundNoticeHeader inboundNoticeHeader = inboundNoticeHeaderService.selectById(headerId);
            if (null == inboundNoticeHeader) {
                return;
            }
            String shipmentGid = inboundNoticeHeader.getSourceKey();
            if (StringUtils.isEmpty(shipmentGid)) {
                return;
            }
            EntityWrapper<OtmOrderRelease> releaseEntityWrapper = new EntityWrapper<>();
            releaseEntityWrapper.eq("osl.lot_no1", vin);
            releaseEntityWrapper.eq("onh.store_house_id", inboundNoticeHeader.getStoreHouseId());
            cancleOutboundList = otmOrderReleaseMapper.queryCancleOutboundCount(releaseEntityWrapper);
        } catch (Exception e) {
            LOGGER.error(" 查询下单指令是否删除失败。。{}", e.getMessage());
        }
        if (CollectionUtils.isNotEmpty(cancleOutboundList)) {
            throw new BaseException("车架号[" + vin + "]最近一次出库指令[" + cancleOutboundList.get(0) + "]已删除,如果要恢复库存,请操作退库");
        }
    }

    public InboundDTO inboundDetailByVinNo(String vinNo, Long houseId) {
        if (Objects.isNull(vinNo)) {
            throw new BaseException("请输入底盘号");
        }
        //2019-1-30 调整多个入库扫码入库提示异常
        EntityWrapper<OtmOrderRelease> reEW = new EntityWrapper<>();
        reEW.eq("qr_code", vinNo);
        reEW.ne("status", TableStatusEnum.STATUS_50.getCode());
        reEW.orderBy("id", false);
        List<OtmOrderRelease> orderReleases = releaseService.selectList(reEW);
        if (CollectionUtils.isNotEmpty(orderReleases)) {
            vinNo = orderReleases.get(0).getVin();
        }
        List<InboundDTO> detailByLotNo = this.baseMapper.getInboundDetailByLotNo(vinNo, houseId);
        if (CollectionUtils.isEmpty(detailByLotNo)) {
            throw new BaseException("未查找到对应信息!" + this.compareDestStoreHouse(vinNo, houseId));
        } else {
            InboundDTO inboundDTO = detailByLotNo.get(0);
            if (Objects.isNull(inboundDTO.getGmtCreate())) {
                inboundDTO.setGmtCreate(new Date());
            }
            return inboundDTO;
        }
    }

    private String compareDestStoreHouse(String vinNo, Long storeHouseId) {
        LOGGER.info("扫码入库查询目的地是否正确！");
        String mesg = "请核对目的地是否为：";
        //通过车架号查询入库通知单详细表
        Wrapper<InboundNoticeLine> ew = new EntityWrapper<>();
        StringBuffer sb = new StringBuffer();
        sb.append(TableStatusEnum.STATUS_50.getCode()).append(",").append(TableStatusEnum.STATUS_30.getCode());
        List<String> status = Arrays.asList(sb.toString().split(","));
        ew.eq("lot_no1", vinNo);
        ew.notIn("status", status);
        ew.orderBy("gmt_create", false);
        LOGGER.info("查询入库通知单信息结果开始。。。。。");
        List<InboundNoticeLine> inboundNoticeLines = inboundNoticeLineMapper.selectList(ew);
        LOGGER.info("查询入库通知单信息结果结束。。。。。" + inboundNoticeLines.size());
        if (CollectionUtils.isNotEmpty(inboundNoticeLines)) {
            InboundNoticeLine inboundNoticeLine = inboundNoticeLines.get(0);
            //通过明细headerid查询头表的仓库id
            Wrapper<InboundNoticeHeader> headerEw = new EntityWrapper<>();
            headerEw.eq("id", inboundNoticeLine.getHeaderId());
            headerEw.ne("status", TableStatusEnum.STATUS_50.getCode());
            headerEw.orderBy("gmt_create", false);
            List<InboundNoticeHeader> inboundNoticeHeader = inboundNoticeHeaderMapper.selectList(headerEw);
            if (CollectionUtils.isNotEmpty(inboundNoticeHeader)) {
                //获取入库仓库id
                Long headerStoreHouseId = inboundNoticeHeader.get(0).getStoreHouseId();
                //如果入库仓库和扫码仓库不一致提示
                if (!(storeHouseId == headerStoreHouseId)) {
                    Storehouse storehouse = storehouseMapper.selectById(headerStoreHouseId);
                    return mesg + storehouse.getName();
                }
            }
        } else {
            Wrapper<OtmOrderRelease> oorEw = new EntityWrapper<>();
            oorEw.eq("vin", vinNo);
            oorEw.ne("status", TableStatusEnum.STATUS_50.getCode());
            oorEw.orderBy("gmt_create", false);
            List<OtmOrderRelease> otmOrderReleases = otmOrderReleaseMapper.selectList(oorEw);
            //只发段
            LOGGER.info("扫码入库直发段查询运单信息：" + otmOrderReleases);
            if (CollectionUtils.isNotEmpty(otmOrderReleases)) {
                return mesg + otmOrderReleases.get(0).getDestLocationName();
            }
        }
        return "";
    }

    public InboundDTO inboundDetailById(String id, Long houseId) {
        try {
            if (Objects.isNull(id)) throw new BaseException("请输入底盘号");
            InboundDTO inboundDTO = this.baseMapper.getInboundDetailById(id, houseId);
            if (Objects.isNull(inboundDTO)) throw new BaseException("未查找到对应信息");
            if (Objects.isNull(inboundDTO.getGmtCreate())) inboundDTO.setGmtCreate(new Date());
            return inboundDTO;
        } catch (BaseException e) {
            LOGGER.error("Service:\t" + e.toString());
            throw e;
        } catch (Exception e) {
            LOGGER.error("Service:\t" + e.toString());
            throw new BaseException("详明查询出现错误");
        }
    }

    public List<StoreAreaAndLocationDTO> queryStoreLocation(Long houseId) {
        List<StoreAreaAndLocationDTO> storeAreaAndLocationDTOS = new ArrayList<>();
        List<StoreLocation> storeLocations = iStoreLocationService.listUsableLocation(houseId);
        for (StoreLocation storeLocation : storeLocations) {
            StoreAreaAndLocationDTO storeAreaAndLocationDTO = getAreaById(storeLocation.getStoreAreaId(),
                    storeAreaAndLocationDTOS);

            if (Objects.isNull(storeAreaAndLocationDTO)) {
                storeAreaAndLocationDTO = new StoreAreaAndLocationDTO();
                storeAreaAndLocationDTO.setStoreAreaId(storeLocation.getStoreAreaId());
                storeAreaAndLocationDTO.setStoreAreaName(storeLocation.getStoreAreaName());
                storeAreaAndLocationDTOS.add(storeAreaAndLocationDTO);
            }

            storeAreaAndLocationDTO.addStoreLocation(storeLocation);
        }
        return storeAreaAndLocationDTOS;
    }

    public String getBarcode(String vinNo) {
        try {
            if (Objects.isNull(vinNo)) throw new BaseException("请绑定车架号");
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            Hashtable<EncodeHintType, String> hints = new Hashtable<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            BitMatrix bitMatrix = multiFormatWriter.encode(vinNo, BarcodeFormat.QR_CODE, 60, 60, hints);
            BufferedImage image = toBufferedImage(bitMatrix);
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ImageIO.write(image, "png", os);
            //Base64 base64 = new Base64();
            BASE64Encoder base64 = new BASE64Encoder();
            return base64.encode(os.toByteArray());
        } catch (Exception e) {
            LOGGER.error("Service:\t" + e.toString());
            throw new BaseException("生成二维码错误");
        }
    }

    /**
     * 车辆停放前/后绑定实车位置
     */
    @Override
    public SkuStore updateBindStoreDetail(CommonConditionParamDTO dto) {
        if (dto == null) {
            throw new BaseException("参数不能为空");
        }
        Map<String, String> condition = dto.getCondition();
        if (condition == null || condition.isEmpty()) {
            throw new BaseException("绑定信息不能为空");
        }
        String houseId = condition.get("houseId");
        String lotNo1 = condition.get("lotNo1");
        String storeDetail = condition.get("storeDetail");
        if (StringUtils.isBlank(storeDetail)) {
            throw new BaseException("实车停放信息不能为空");
        }
        if (StringUtils.isBlank(houseId)) {
            throw new BaseException("仓库id不能为空");
        }
        if (StringUtils.isBlank(lotNo1)) {
            throw new BaseException("车架号不能为空");
        }
        SkuStore skuStore = new SkuStore();
        skuStore.setStoreHouseId(Long.valueOf(houseId));
        skuStore.setStoreDetail(storeDetail);
        skuStore.setVin(lotNo1);
        skuStore.setUserCreate(userService.getLoginUser().getName());
        skuStore.setGmtCreate(new Date());
        skuStoreService.insert(skuStore);
        return skuStore;
    }

    static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? black : white);
            }
        }
        return image;
    }

    private StoreAreaAndLocationDTO getAreaById(Long storeAreaId, List<StoreAreaAndLocationDTO> storeAreaAndLocationDTOS) {
        for (StoreAreaAndLocationDTO storeAreaAndLocationDTO : storeAreaAndLocationDTOS) {
            if (storeAreaAndLocationDTO.getStoreAreaId().equals(storeAreaId)) {
                return storeAreaAndLocationDTO;
            }
        }
        return null;
    }
}
